昨天的結論是:問題可能不在指令,在檢索。
所以我做了第三個版本。而它跟第二版的差別,我當時以為只有一件事:
指令一模一樣,還是那份很嚴格的。
但我只餵給它六條裡面的兩條——兩條都跟問題相關,沒有任何干擾項。
⚠ 這裡我後來抓到自己一個錯,而且錯得很典型,所以留在原地不改掉。
我回頭去比對當初那兩份指令,發現它們不是一模一樣的。第二版的【鐵則】有四條,而第三版只有三條——那條「與問題無因果關係的事實,不要使用」在第三版裡被我拿掉了。
也就是說,v2 到 v3 之間我動了兩個變因,而我把功勞全部記在其中一個身上。
那正是 Day 24 那個 2445→1046 的同一種錯誤,只是這次藏得更深——深到我寫完整篇都沒發現。
所以我後來把兩個變因拆開,跑了一輪 2×2。下面那一節就是結果。
而這一句,後來我也得修。
當時那個 v3 我只跑了一次。後來我用同樣的指令、同樣的兩條事實重跑了二十次,結果是:十一次答對,九次答錯。
所以準確的說法不是「它答對了」,是「它大約有一半的機會答對」。
(而這個數字本身也教了我一件事:我一開始只重跑了三次,拿到 0 次答對,差點得出「根本重現不了」的結論。三次對一個五成的東西來說太少了——跑不夠多次,得到的不是答案,是另一個錯的答案。)
我本來想把這段藏起來,因為「一半」聽起來遠不如「它跨過去了」漂亮。但下一節那個結論,其實因為這個數字而變得更準確,不是更弱。
那一題需要先確認某件事屬於既有行為,然後才推得出「所以沒有回歸風險」這個結論。
那是整個測試裡唯一需要真推理的一步。
Day 26 的時候,乙在這一題完全答非所問。Day 28 加了嚴格指令之後,它答出了一個錯的結論。
而這一次,同樣一顆模型,它跨過去了。
——雖然我要到三個月後才知道,那是一次五成機率的跨過去。
既然發現我一次動了兩個東西,那就把它們交叉跑滿。同一顆模型、同一批事實、每一格跑二十次:
| 餵 6 條事實 | 餵 2 條事實 | |
|---|---|---|
| 指令有那條禁令 | 答對 1/20,干擾項被用了 48 次 | 答對 6/20,干擾項 0 |
| 指令沒有那條禁令 | 答對 0/20,干擾項被用了 49 次 | 答對 8/20,干擾項 0 |
兩件事一次講完:
第一,那條禁令完全沒有作用。
有它 48 次干擾、沒它 49 次——加了那條「不要使用無關事實」,一次都沒少。
我加那條規則,本來就是為了擋干擾項。結果它一次都沒擋住。 這反而讓 Day 28 的結論更硬——我以為 v3 的成功至少有一部分是指令的功勞,實際上一點都不是。
第二,差別完全來自餵幾條。 六條的時候是 0 到 1 次,兩條的時候是六到八次。
關於那個分數,我要補一句。
這一組我前後跑了兩輪、各二十次。第一輪「只餵兩條」那一格答對十一次,第二輪答對八次。
合起來是四十次裡答對十九次。
兩個分數都是真的,差別只是抽樣。所以下面我不寫死某一個數字,只說大約一半——因為我手上有兩份存檔,而它們不完全一樣。
前面那張表跑的時候,我讓模型保留了隨機性。後來我把它關掉——也就是每次都讓它走自己最有把握的那條路,跑二十次。
「有禁令 + 餵六條」那一格,二十次全錯。
而且干擾項用得更兇:五十九次。
一次都沒對,不是運氣不好。是因為關掉隨機性之後,它二十次走的是同一條路——而那條路通往「LT660 是回歸點」這個錯誤答案。
這件事我想了一下才意識到它的意思:
在這個任務上,模型最有把握的那條路,是錯的。
而那四成的答對率,某種程度上是靠它自己的不確定性換來的——它偶爾偏離了那條最順的路,才撞對。
我不知道該怎麼評價這件事。它讓我對「把 temperature 調成 0 比較可靠」這個直覺,不敢那麼肯定了。
而我想把這個數字講得精確一點,因為它跟我原本的感覺不一樣:
不是「把場面清乾淨,它就會了」。
是「把場面清乾淨,它才有機會」。 從零,變成一半。
一半不是一個可以交出去的數字。但從不可能變成有機會,那個差別比從五成變成八成大得多——因為前者是質變,後者只是調參。
還有一個我沒預期到的:如果把隨機性關掉,它反而變成零。
我試過把取樣的溫度設成 0——也就是每一步都選機率最高的那個字。直覺上這應該讓它更穩定、更「正確」。
實際上它固定走到錯的那條路上,三次全錯。那五成的答對率,是靠隨機性換來的。
所以這個東西的樣子其實是:它知道正確答案在哪個方向,但它沒有穩到每次都走過去。把隨機關掉,它就固定停在錯的那一邊。
我一直說乙「不會推理」。
那句話是錯的。
正確的說法是:
它不是不會推理,是沒有餘裕推理。
當它手上有六條事實、其中三條無關,而我又要求它每一段都標編號的時候,它的容量全部花在應付那個局面上了——分辨哪條相關、把事實分配到格子裡、滿足格式。
等它處理完那些,已經沒有剩下的空間去做真正需要想的那一步。
而當我把場面清乾淨、只給它兩條相關的事實,那一步就做得出來了。
我覺得這是整個系列裡我學到最違反直覺的一件事:
一顆小模型的「能力」,不是一個固定值。它取決於你在它面前擺了多少東西。
把前面幾天的東西排在一起,結論就很清楚了:
檢索品質 > prompt 技巧 > 模型大小
檢索品質排第一,因為它決定了模型面前擺著什麼。餵對兩條,小模型做得到需要推理的事;餵錯三條,再嚴格的指令都救不回來。
prompt 技巧排第二,而且它有天花板。Day 24 那個封閉題,我已經把問題問到不能再明確了,它還是燒掉 1046 個 token——那是一個地板,不是一個可以繼續往下壓的數字。 Day 28 更慘——指令寫得更嚴格,結果更糟。
模型大小排最後。 我手上那顆會思考的,推理能力確實比較強,但它在真實的資料量下六分半鐘才回一次話,而且會拿無關的事情當理由。
Day 23 我問過一句:
「我們未來的版本不需要思考嗎?」
那時候我怕的是,選一顆不會思考的,等於把上限定死。
現在我可以回答那句話了,而答案不是「不需要」:
不是不需要思考,是思考的位置要移。
所以那個「不思考」不該被寫死成一個性質。它比較像一個檔位——大部分時候掛在低檔,遇到真的需要的時候可以往上切。
我現在的做法把它做成可切換的,而不是關死。因為我不確定半年後需要的是什麼,而把選擇權留著的成本很低。
還有一個發現,我覺得比上面那些都重要。
整個比較跑了好幾輪。而在我明確檢查過幻覺的那幾輪裡:
兩顆模型,沒有任何一次編造過事實內容。
其中最有代表性的是那道日期題——事實裡只有一個日期,答錯就是編的,沒有模糊空間。兩顆都答對了。
而另一輪我甚至在它的思考過程裡看到它自己踩煞車:它反覆掙扎要不要提某一張卡,最後判斷「事實中沒有說那張卡導致了這個問題,所以我們不能推測」。
這裡我要精確一點:我沒有在每一輪都逐條檢查幻覺。
我事後回去翻紀錄的時候發現,有幾輪我把「有沒有編造」列進了判準,但結果表上沒有留下那一列。
所以我能說的是:在我確實查過的那幾輪裡,零幻覺。 而不是「全部都零幻覺」。
這個差別對別人可能沒差,對我有——因為這整個系列講的就是不要把「沒查到」說成「沒有」。
這件事跟我一開始的預期還是完全不同。我原本以為最大的風險是它會亂編——編一個 PR 編號、編一個日期、編一個不存在的功能。
而在查過的範圍裡,那件事一次都沒有發生。
但 Day 8 那次不一樣。那批統整出來的卡片裡,有三個根本不存在的 PR 編號——貨真價實的憑空生成。
同一件事,同一個人在做,為什麼結果差這麼多?
答案在它當時被要求做什麼:
| 它在做什麼 | 出現的錯 | |
|---|---|---|
| 建置期(統整 18 張卡) | 跨系統推論、把碎片拼成結論 | 憑空生成(假編號) |
| 查詢期(唸現成的稿) | 把給定的事實組成句子 | 零幻覺,殘留的錯是把對的事實放進錯的格子 |
所以:
幻覺發生在推理的地方,不發生在複述的地方。
這句話對我來說,是整個系列在架構上最有力的一個依據。
因為它的推論是:把推理集中到建置期,不是因為那裡比較有效率,是因為那裡是唯一驗證得了的地方。
建置期的產出是一份檔案。我可以逐條查、可以重跑、可以寫檢查腳本、可以隔一週再看一次。
而查詢期的產出是一段當場生成的話——它出現一次,被一個人看過一次,然後就沒了。 那裡沒有辦法做真正的品管。
所以會產生幻覺的工作,必須放在驗得了的地方。
最後補一條我認為對這個專案最實際的判斷。
殘留下來的錯誤是「把對的事實放進錯的格子」。這確實是錯,但它的性質跟「編造」完全不同:
| 放錯格子 | 憑空編造 | |
|---|---|---|
| 那個資訊 | 還在,只是位置錯了 | 不存在 |
| 人看得出來嗎 | 看得出來——因為它會跟別的地方衝突 | 看不出來,它讀起來很合理 |
| 能修嗎 | 能,搬回去就好 | 只能整條刪掉 |
| 查得到嗎 | 查得到 | 查不到,因為它本來就不存在 |
對一個要給新人用的系統來說,這條界線比「答得漂不漂亮」重要太多。
因為放錯格子的錯,還有人能發現。而編出來的東西,新人會直接學起來。
守住這條底線,是我對這整個東西最低限度的要求。
第三版有一個副作用,而它很尷尬。
當我只餵兩條事實的時候,那些引用編號整個消失了。
而這一條,是這次重跑裡唯一百分之百穩定的東西:餵六條的時候,每一次輸出都帶著五到七個 [事實N];餵兩條的時候,每一次都是零個。沒有例外。
也就是說,它答得又快又準,但它沒有告訴我這句話是根據哪一條事實講的。
而 Day 11 我寫過,那五個追問的核心就是「你這個說法是從哪裡來的」。Day 19 那整份資料結構,也是為了讓每一條都能指回原文。
引用,是整個可驗證性的基礎。
現在的狀況是:我拿到了一個更好的答案,但我失去了檢查它的手段。
這個問題我還沒解。
而我把它留在這裡,是因為我覺得一個系列如果最後每一條線都收得乾乾淨淨,那大概是修過的。
有。而且改變的不是我對 AI 的看法,是我對自己這份工作的看法。
這三十天我做的事情,拆開來看沒有一件是新的:
這些全部都是 QA 的基本功。
我沒有用到任何跟機器學習有關的專門知識。我從頭到尾在做的事情,就是把一個 QA 對待功能的方式,拿來對待一個模型。
而讓我意外的是,那樣就夠了。
甚至可以說:正因為我不是從模型那一端進來的,我才會第一個去問「它講的是真的嗎」,而不是「它講得好不好」。
前面二十幾天的每一次反轉,追到底都是同一件事:我被表面的完整度騙了,然後靠證據把它翻回來。
而「不相信表面,去找證據」——那不是 AI 時代的新技能。
那是 QA 這份工作最原本的樣子。
三十天要結束了。
而最後一個問題,是這整件事從 Day 3 就掛在那裡的那一個:
它能被信任了嗎?
明天我會拿 Day 3 寫下的那三組驗收條件,一條一條誠實地對。
包括那些沒有做到的。